package com.hy.util;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.*;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

import java.util.Arrays;

/**
 * date:2020/12/18
 * description:日志类  专门在方法前后记录日志
 *          通知方法后面的参数个数和类型不要随便写，spring只认识JoinPoint，这个参数里面
 *          放了目标方法的信息。
 *          如果加其他参数，要告诉spring这个参数是什么？
 *
 *          start(JoinPoint jp)
 * Author:gxh
 */

//@Aspect:说明LogUtil是切面类
@Component("util")
//@Aspect
//@Order(2)
public class LogUtil {

    //定义一个没有返回值的空方法。作用：抽取出可复用的切入点表达式，@Pointcut定义切入点表达式
    //使用的时候 使用它的方法名称
    //切入点表达式：修饰符（可以省略） 返回类型 方法完整的签名(包名+类名+方法名) 参数列表
    //返回类型不能省，如果是空返回， 就写void
    //*  ：可以匹配任意字符 或者一级目录
    //..  可以匹配任意多个任意类型的参数
//    @Pointcut(value = "execution(* com.hy.impl.RentImpl.*(..))")
    public void pc(){};
//    try{
//        //前置通知
//        Object re = method.invoke();
//        //返回通知
//        return re;
//    }catch(){
//        //异常通知
//    }finally{
//        //后置通知 最终通知
//    }

    //表示这个方法是前置通知方法
    //value写切入点表达式

    //修饰符（可以省略） 返回类型 方法完整的签名 参数列表
//    @Before(value = "pc()")
    public void start(JoinPoint jp){
        //JoinPoint jp  包含目标方法的一些信息 包括方法名和参数

        //jp.getSignature():获取方法签名信息
        Signature signature = jp.getSignature();
        //获取方法名
        String name = signature.getName();

        //获取调用方法的参数
        Object[] args = jp.getArgs();
        System.out.println("LogUtil before通知"+name+"方法开始执行,参数是"+ Arrays.asList(args));
    }

    //返回通知
    //获取返回结果 ，1.在通知方法上再加一个参数，
    //            2.在AfterReturning注解上加一个属性returning，值就是参数变量名，告诉spring这个参数是返回结果，
//    @AfterReturning(value = "pc()",returning = "result")
    public static void returnResult(JoinPoint jp,Object result){

        System.out.println("LogUtil切面AfterReturning通知"+jp.getSignature().getName()+"方法执行,返回结果是："+result);
    }

    //异常通知
    @AfterThrowing(value = "pc()",throwing = "e")
    public static void throwEx(JoinPoint jp,Exception e){

        System.out.println("LogUtil切面AfterThrowing通知"+jp.getSignature().getName()+"方法执行出现异常===,异常是"+e.getMessage());
    }

    //最终结束通知
//    @After(value = "pc()")
    public static void end(){
        System.out.println("LogUtil切面After通知  方法最终执行结束===");
    }

//    环绕通知必须要有返回类型
    //执行目标方法的时候必须处理异常
    //在目标方法执行前后添加增强逻辑
//    @Around(value = "pc()")
    public Object around(ProceedingJoinPoint pjp){
        Object result = null;
//
        try {
            System.out.println("环绕通知的前置");

//            pjp.proceed(); 相当于method.invoke(obj, args);作用是执行目标方法
            result = pjp.proceed(pjp.getArgs());
            System.out.println("环绕通知的返回,结果是"+result);
        } catch (Throwable throwable) {
//            throwable.printStackTrace();
            System.out.println("环绕通知的异常"+throwable.getMessage());
        }finally {
            System.out.println("环绕通知的最终结束");
        }
        return result;
    }
}
